﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Robocop.Cerebro
{
    public class Carta
    {
        #region Atributos
        private ValorCarta valorCarta;
        private Naipe naipe;
        #endregion

        #region Propriedades
        public ValorCarta ValorCarta
        {
            get { return valorCarta; }
            set { valorCarta = value; }
        }

        public Naipe Naipe
        {
            get { return naipe; }
            set { naipe = value; }
        }
        #endregion

        #region Construtoras
        public Carta()
        {
        }

        public Carta(ValorCarta valorCarta, Naipe naipe)
        {
            this.valorCarta = valorCarta;
            this.naipe = naipe;
        }
        #endregion

        #region Métodos
        public static decimal calculaProbabilidadeDupla(List<Carta> cartasMao, List<Carta> cartasComunitarias)
        {
            if (cartasMao.Count < 2)
            {
                return 0;
            }

            // possui dupla na mão
            if (possuiDupla(cartasMao))
            {
                return 1;
            }
            // se possui dupla nas cartas comunitárias
            else if (possuiDupla(cartasComunitarias))
            {
                return 1;
            }

            Carta carta1 = cartasMao[0];
            Carta carta2 = cartasMao[1];
            
            decimal probabildiadeJogoCarta1 = calculaProbabilidadeDupla(carta1, cartasComunitarias);
            decimal probabildiadeJogoCarta2 = calculaProbabilidadeDupla(carta2, cartasComunitarias);

            if (probabildiadeJogoCarta1 == 1 || probabildiadeJogoCarta2 == 1)
            {
                return 1;
            }
            else
            {
                return probabildiadeJogoCarta1 + probabildiadeJogoCarta2;
            }
        }

        private static decimal calculaProbabilidadeDupla(Carta carta, List<Carta> cartasComunitarias)
        {
            if (carta == null || cartasComunitarias.Count == 0)
            {
                return 0;
            }

            // Verifica se já tem a dupla
            foreach (Carta c in cartasComunitarias)
            {
                if (c.ValorCarta == carta.ValorCarta)
                {
                    return 1;
                }
            }

            if (cartasComunitarias.Count == 5)
            {
                return 0;
            }
            
            return 3M / (52M - ((decimal)cartasComunitarias.Count) - 2M);
        }

        private static bool possuiDupla(List<Carta> cartas)
        {
            var lista = 
                from carta1 in cartas join carta2 in cartas on carta1.ValorCarta equals carta2.ValorCarta
                where (carta1.ValorCarta == carta2.ValorCarta && carta1.Naipe != carta2.Naipe)
                select carta1;

            return lista.Count() > 1;
        }

        public static decimal calculaProbabilidadeDuasDuplas(List<Carta> cartasMao, List<Carta> cartasComunitarias)
        {
            if (cartasMao.Count < 2)
            {
                return 0;
            }

            decimal probabildiadeJogoCarta1 = 0;
            decimal probabildiadeJogoCarta2 = 0;

            if (possuiDupla(cartasMao))
            {
                if (possuiDupla(cartasComunitarias))
                {
                    return 1;
                }
                else
                {
                    foreach (Carta c in cartasComunitarias)
                    {
                        List<Carta> lista = new List<Carta>(cartasComunitarias);
                        lista.Remove(c);
                        probabildiadeJogoCarta2 += calculaProbabilidadeDupla(c, lista);
                    }

                    return probabildiadeJogoCarta2;
                }
            }
            else if (possuiDupla(cartasComunitarias))
            {
                foreach (Carta c in cartasMao)
                {
                    probabildiadeJogoCarta2 += calculaProbabilidadeDupla(c, cartasComunitarias);
                }

                return probabildiadeJogoCarta2;
            }

            Carta carta1 = cartasMao[0];
            Carta carta2 = cartasMao[1];

            probabildiadeJogoCarta1 = calculaProbabilidadeDupla(carta1, cartasComunitarias);
            probabildiadeJogoCarta2 = calculaProbabilidadeDupla(carta2, cartasComunitarias);

            return probabildiadeJogoCarta1 * probabildiadeJogoCarta2;
        }

        #endregion
    }
}
